package cn.wolfcode.wolf2w.business.service.impl;

import cn.wolfcode.wolf2w.api.RemoteDestinationService;
import cn.wolfcode.wolf2w.api.domain.*;
import cn.wolfcode.wolf2w.business.mapper.StrategyCatalogMapper;
import cn.wolfcode.wolf2w.business.mapper.StrategyContentMapper;
import cn.wolfcode.wolf2w.business.mapper.StrategyMapper;
import cn.wolfcode.wolf2w.business.mapper.StrategyThemeMapper;
import cn.wolfcode.wolf2w.business.query.StrategyQuery;
import cn.wolfcode.wolf2w.business.service.IStrategyService;
import cn.wolfcode.wolf2w.business.util.DateUtil;
import cn.wolfcode.wolf2w.business.vo.ThemeVO;
import cn.wolfcode.wolf2w.common.core.context.SecurityContextHolder;
import cn.wolfcode.wolf2w.common.redis.service.RedisService;
import cn.wolfcode.wolf2w.common.redis.util.RedisKeys;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 攻略Service业务层处理
 *
 * @author 浪兎兎
 * @date 2025-05-30
 */
@Service
@Transactional
public class StrategyServiceImpl extends ServiceImpl<StrategyMapper, Strategy> implements IStrategyService {

    @Autowired
    private StrategyThemeMapper strategyThemeMapper;
    @Autowired
    private StrategyCatalogMapper strategyCatalogMapper;
    @Autowired
    private StrategyContentMapper strategyContentMapper;
    @Autowired
    private RemoteDestinationService destinationService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private StrategyRankServiceImpl strategyRankService;
    @Autowired
    private AmqpTemplate amqpTemplate;

    @Override
    public IPage<Strategy> queryPage(StrategyQuery qo) {
        IPage<Strategy> page = new Page<>(qo.getCurrentPage(), qo.getPageSize());
        return lambdaQuery()
                .page(page);
    }

    @Override
    public List<Strategy> getViewNumberTop3(Long destId) {
        return lambdaQuery().eq(Strategy::getDestId, destId)
                .orderByDesc(Strategy::getViewnum)
                .last("limit 3")
                .list();
    }

    @Override
    public int strategySave(Strategy strategy) {
        String themeName = strategyThemeMapper.selectById(strategy.getThemeId()).getName();
        strategy.setThemeName(themeName);
        // 设置目的地相关
        StrategyCatalog catalog = strategyCatalogMapper.selectById(strategy.getCatalogId());
        strategy.setCatalogName(catalog.getName());
        strategy.setDestId(catalog.getDestId());
        strategy.setDestName(catalog.getDestName());
        // 设置基础数据
        strategy.setCreateTime(new Date());
        strategy.setViewnum(0);
        strategy.setReplynum(0);
        strategy.setFavornum(0);
        strategy.setSharenum(0);
        strategy.setThumbsupnum(0);
        // 判断是否国内外
        List<Destination> inner = destinationService.getOneToasts(strategy.getDestId(), "inner").getData();
        if (inner.get(0).getName().equals("中国")) {
            strategy.setIsabroad(0);
        } else {
            strategy.setIsabroad(1);
        }
        // 插入
        baseMapper.insert(strategy);
        // 插入正文
        Long id = strategy.getId();
        String content = strategy.getContent().getContent();
        StrategyContent strategyContent = new StrategyContent(id, content);
        strategyContentMapper.insert(strategyContent);

        return 1;
    }

    /**
     * 阅读量自增
     *
     * @param sid 攻略id
     * @return 状态数据
     */
    @Override
    public Map<String, Object> getViewStatusNumber(Long sid) {
        // 初始化
        String key = strategyHashInit(sid);
        // 添加播放量
        redisService.incrementCacheMapValue(key, "viewnum", 1L);
        // 返回数据
        return redisService.getCacheMap(key);
    }

    @Override
    public Map<String, Object> favor(Long sid) {
        // 初始化 攻略状态
        String strategyHashKey = strategyHashInit(sid);
        // 收藏初始化
        String userFavorKey = favorInit();
        // 判断是否收藏过
        boolean flg = true;
        if (redisService.isCacheSetContains(userFavorKey, sid)) {
            // 收藏 删除
            redisService.deleteCacheSetValue(userFavorKey, sid);
            redisService.incrementCacheMapValue(strategyHashKey, "favornum", -1L);
            flg = false;
        } else {
            // 未收藏 添加
            redisService.addCacheSetValue(userFavorKey, sid);
            redisService.incrementCacheMapValue(strategyHashKey, "favornum", 1L);
        }
        // 返回数据
        Map<String, Object> cacheMap = redisService.getCacheMap(strategyHashKey);
        cacheMap.put("result", flg);
        return cacheMap;
    }

    @Override
    public boolean isFavor(Long sid, Long uid) {
        String userFavorKey = RedisKeys.STRATEGY_FAVOR.join(uid.toString());
        return redisService.isCacheSetContains(userFavorKey, sid);
    }

    /**
     * 点赞
     *
     * @param sid 攻略id
     * @return 是否成功
     */
    @Override
    public Map<String, Object> thumbsup(Long sid) {
        // 初始化
        Long userId = SecurityContextHolder.getUserId();
        String key = RedisKeys.STRATEGY_THUMBSUP.join(userId.toString(), sid.toString());
        String hashKey = RedisKeys.STRATEGY_STATUS_HASH.join(sid.toString());
        // key 是否存在
        if (!redisService.hasKey(key)) {
            long time = DateUtil.getDayBetween(DateUtil.getEndTime4day(), new Date());
            if (time == 0) {
                redisService.setCacheObject(key, 0, 1L, TimeUnit.DAYS);
            } else {
                redisService.setCacheObject(key, 0, time, TimeUnit.SECONDS);
            }
        }
        // value 是否大于5，如果是，则失败
        if (((int) redisService.getCacheObject(key)) >= 5L) {
            // 失败
            Map<String, Object> cacheMap = redisService.getCacheMap(hashKey);
            cacheMap.put("result", false);
            return cacheMap;
        } else {
            // 成功
            redisService.incrementCacheObjectValue(key, 1L);
            redisService.incrementCacheMapValue(hashKey, "thumbsupnum", 1L);
            Map<String, Object> cacheMap = redisService.getCacheMap(hashKey);
            cacheMap.put("result", true);
            return cacheMap;
        }
    }

    /**
     * 评论数 + 1
     *
     * @param sid 攻略 id
     * @return 状态
     */
    @Override
    public Map<String, Object> getReplyNumber(Long sid) {
        // 初始化
        String key = strategyHashInit(sid);
        // 添加播放量
        redisService.incrementCacheMapValue(key, "replynum", 1L);
        // 返回数据
        return redisService.getCacheMap(key);
    }

    /**
     * 攻略持久化
     */
    @Override
    public void statusPersistence() {
        String keys = RedisKeys.STRATEGY_STATUS_HASH.join("*");
        List<Strategy> strategies = redisService.keys(keys).stream().map(s -> {
            Map<String, Object> cacheMap = redisService.getCacheMap(s);
            Strategy strategy = new Strategy();
            strategy.setId((Long) cacheMap.get("id"));
            strategy.setViewnum((Integer) cacheMap.get("viewnum"));
            strategy.setReplynum((Integer) cacheMap.get("replynum"));
            strategy.setFavornum((Integer) cacheMap.get("favornum"));
            strategy.setSharenum((Integer) cacheMap.get("sharenum"));
            strategy.setThumbsupnum((Integer) cacheMap.get("thumbsupnum"));
            return strategy;
        }).collect(Collectors.toList());
        updateBatchById(strategies);
    }

    @Override
    public void strategyRankStatis() {
        List<Strategy> abroadList =
                query().select("dest_id, dest_name, id, title ,viewnum")
                        .eq("isabroad", 1)
                        .orderByDesc("viewnum")
                        .last("limit 10")
                        .list();

        List<Strategy> chinaList =
                query().select("dest_id, dest_name, id, title ,viewnum")
                        .eq("isabroad", 0)
                        .orderByDesc("viewnum")
                        .last("limit 10")
                        .list();

        List<Strategy> hotList =
                query().select("dest_id, dest_name, id, title ,viewnum")
                        .orderByDesc("viewnum")
                        .last("limit 10")
                        .list();
        List<StrategyRank> strategyRanks = new ArrayList<>();
        Date now = new Date();

        createRank(abroadList, strategyRanks, now, 1l);
        createRank(chinaList, strategyRanks, now, 2l);
        createRank(hotList, strategyRanks, now, 3l);

        strategyRankService.saveBatch(strategyRanks);
    }

    @Override
    public void statisHashPersistence() {
        String key = RedisKeys.STRATEGY_STATUS_HASH.join("*");
        Collection<String> keys = redisService.keys(key);
        List<Strategy> list = new ArrayList<>();
        for (String s : keys) {
            Map<String, Object> cacheMap = redisService.getCacheMap(s);
            Strategy strategy = new Strategy();
            strategy.setId((Long) cacheMap.get("id"));
            strategy.setViewnum(((Integer) cacheMap.get("viewnum")));
            strategy.setReplynum(((Integer) cacheMap.get("replynum")));
            strategy.setFavornum(((Integer) cacheMap.get("favornum")));
            strategy.setSharenum(((Integer) cacheMap.get("sharenum")));
            strategy.setThumbsupnum(((Integer) cacheMap.get("thumbsupnum")));
            list.add(strategy);
        }
        this.updateBatchById(list);
    }

    @Override
    public void reSendStrategyMessage() {
        long now = System.currentTimeMillis();
        long max = now - 60*1000;
        String key = RedisKeys.MQ_MESSAGE.join("strategy");
        Set set = redisService.rangeCacheZsetByScore(key, 0, max);
        for (Object o : set) {
            String message = (String) o;
            amqpTemplate.convertAndSend("strategyExchange", "", message);
        }
    }

    @Override
    public List<ThemeVO> queryTheme() {
        QueryWrapper<Strategy> qw = new QueryWrapper<>();
        qw.select("theme_id themeId, theme_name themeName, GROUP_CONCAT(DISTINCT dest_name) destName,GROUP_CONCAT(DISTINCT dest_id) destId");
        qw.groupBy("theme_id, theme_name");
        List<Map<String, Object>> list = baseMapper.selectMaps(qw);
        List<ThemeVO> themeVOS = new ArrayList<>();
        for (Map<String, Object> map : list) {
            String themeName = (String) map.get("themeName");
            String destId = (String) map.get("destId");
            String destName = (String) map.get("destName");
            String[] names = destName.split(",");
            String[] ids = destId.split(",");
            List<Destination> dests = new ArrayList<>();
            for (int i = 0; i < ids.length; i++) {
                Long id = Long.valueOf(ids[i]);
                String name = names[i];

                Destination destination = new Destination();
                destination.setId(id);
                destination.setName(name);
                dests.add(destination);
            }
            ThemeVO themeVO = new ThemeVO(themeName, dests);
            themeVOS.add(themeVO);
        }
        return themeVOS;
    }

    private void createRank(List<Strategy> list, List<StrategyRank> strategyRanks, Date now, Long type) {
        for (Strategy strategy : list) {
            StrategyRank strategyRank = new StrategyRank();
            strategyRank.setStrategyId(strategy.getId());
            strategyRank.setStrategyTitle(strategy.getTitle());
            strategyRank.setDestId(strategy.getDestId());
            strategyRank.setDestName(strategy.getDestName());
            strategyRank.setType(type.intValue());
            strategyRank.setStatisTime(now);
            strategyRank.setStatisnum(strategy.getViewnum());
            strategyRanks.add(strategyRank);
        }
    }

    /**
     * 收藏初始化
     *
     * @return redis key
     */
    private String favorInit() {
        // 获取当前登录用户
        Long userId = SecurityContextHolder.getUserId();
        // 初始化 strategy_favor
        String userFavorKey = RedisKeys.STRATEGY_FAVOR.join(userId.toString());
        if (!redisService.hasKey(userFavorKey)) {
            HashSet<Long> sids = new HashSet<Long>() {
                {
                    this.add(-1L);
                }
            };
            redisService.setCacheSet(userFavorKey, sids);
        }
        return userFavorKey;
    }

    /**
     * 攻略状态初始化
     *
     * @param sid 攻略id
     * @return redis key
     */
    private String strategyHashInit(Long sid) {
        String key = RedisKeys.STRATEGY_STATUS_HASH.join(sid.toString());
        // 判断是否存在
        if (!redisService.hasKey(key)) {
            // 不存在，则需要到 MySQL 同步
            Strategy strategy = baseMapper.selectById(sid);
            Map<String, Object> status;
            // 如果 MySQL 也没有，为了防止穿透，设置所有数据为0
            if (strategy == null) {
                return key;
            } else {
                status = new HashMap<String, Object>() {
                    {
                        this.put("viewnum", strategy.getViewnum());
                        this.put("replynum", strategy.getReplynum());
                        this.put("favornum", strategy.getFavornum());
                        this.put("sharenum", strategy.getSharenum());
                        this.put("thumbsupnum", strategy.getThumbsupnum());
                        this.put("id", strategy.getId().intValue());
                    }
                };
            }
            // 存入 redis
            redisService.setCacheMap(key, status);
        }
        return key;
    }


}
